package org.example;

import org.example.exception.InputFormatException;

import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Expression {
    private BigDecimal num1;
    //TODO 第一个数

    private BigDecimal num2;
    //TODO 第二个数

    private char sign;
    //TODO 运算符

    private String result;
    //TODO 运算结果

    private static final Pattern DIVIDE_ZERO_PATTERN = Pattern.compile("^-?0(\\.0+)?$");
    //TODO 检查除数是否为零正则式

    private static final Pattern INPUT_PATTERN = Pattern.compile("^(-?\\d+(\\.\\d+)?)(\\s*)[+\\-*/^](\\s*)((\\d+(\\.\\d+)?)|(\\(-\\d+(\\.\\d+)?\\)))$");
    //TODO 检查输入表达式是否合法正则式

    private static final Set<Character> OPERATOR_SET=new HashSet<>();

    static {
        OPERATOR_SET.add('+');
        OPERATOR_SET.add('-');
        OPERATOR_SET.add('*');
        OPERATOR_SET.add('/');
        OPERATOR_SET.add('^');
    }

    public Expression() {
    }

    public Expression(String input) {
        init(input);
    }

    //TODO 初始化对象并结算表达式结果
    private void init(String input) {
        checkInputFormat(input);
        //去除空格等无效字符
        String formattedInput = input.replaceAll("[ ()\\s]", "");
        //找到运算符的下标对计算式中的数和运算符进行切割
        for (int charIndex = 1; charIndex < formattedInput.length(); charIndex++) {
            char c = formattedInput.charAt(charIndex);
            if (OPERATOR_SET.contains(c)) {
                String num1 = formattedInput.substring(0, charIndex);
                char sign = formattedInput.charAt(charIndex);
                String num2 = formattedInput.substring(charIndex + 1);
                checkDivideZero(sign, num2);
                setAll(num1, num2, sign);
                return;
            }
        }
        throw new InputFormatException("输入格式不合法!!!");
    }

    //TODO 重置各个属性值
    private void setAll(String num1, String num2, char sign) {
        BigDecimal numberBigDecimal1 = new BigDecimal(num1);
        BigDecimal numberBigDecimal2 = new BigDecimal(num2);
        String result = Calculate.calculate(numberBigDecimal1, numberBigDecimal2, sign);
        setNum1(numberBigDecimal1);
        setNum2(numberBigDecimal2);
        setSign(sign);
        setResult(result);
    }

    //TODO 打印结果(含计算式)
    public void printResult() {
        System.out.println(toString());
    }

    @Override
    public String toString() {
        return num1.toString()
                + sign
                + num2.toString()
                + " = "
                + result;
    }

    //TODO 检查除数是否为0
    private static void checkDivideZero(char sign, String num) {
        if (sign != '/') {
            return;
        }
        //使用正则表达式检测进行除法运算时除数是否为0
        Matcher matcher = DIVIDE_ZERO_PATTERN.matcher(num);
        boolean matches = matcher.matches();
        if (matches) {
            throw new ArithmeticException("除数不能为0!!!");
        }
    }

    //TODO 检查输入格式是否合法
    private static void checkInputFormat(String input) {
        //使用正则表达式检测输入格式是否正确
        Matcher matcher = INPUT_PATTERN.matcher(input);
        boolean matches = matcher.matches();
        if (!matches) {
            throw new InputFormatException("输入格式不合法!!!");
        }
    }

    public BigDecimal getNum1() {
        return num1;
    }

    public void setNum1(BigDecimal num1) {
        this.num1 = num1;
    }

    public BigDecimal getNum2() {
        return num2;
    }

    public void setNum2(BigDecimal num2) {
        this.num2 = num2;
    }

    public char getSign() {
        return sign;
    }

    public void setSign(char sign) {
        this.sign = sign;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }
}
